package per.dj.testpro.netty;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import per.dj.testpro.entity.GpsConnection;
import per.dj.testpro.entity.protocol.Message;
import per.dj.testpro.service.MessageService;

import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@Component
@Qualifier("serverHandler")
@ChannelHandler.Sharable
public class ServerHandler extends SimpleChannelInboundHandler<Object> {

    private static final Logger LOGGER = LoggerFactory.getLogger(ServerHandler.class);

    private static ConcurrentMap<String, GpsConnection> connctionMap = new ConcurrentHashMap<String, GpsConnection>();

    @Autowired
    private MessageService messageService;

    @Override
    public void channelRead0(ChannelHandlerContext ctx, Object obj)
            throws Exception {
        LOGGER.info("client msg:"+ obj.toString());

        if (obj instanceof Message) {
            Message tm = (Message) obj;
            GpsConnection conn = this.getConnection(ctx, tm);
            if (conn != null) {
                conn.setConnected(true);

                if (conn.getPackageNum() == Integer.MAX_VALUE) {
                    conn.setPackageNum(0);
                    conn.setErrorPacketNum(0);
                    conn.setErrorPacketNum(0);
                }

                conn.setPackageNum(conn.getPackageNum() + 1);

                messageService.processMsg(tm);

            }
        }

     //添加处理请求的逻辑
    }

    private GpsConnection getConnection(ChannelHandlerContext ctx, Message msg) {
        if (msg == null || msg.getHeader().getSimId() == null) {
            LOGGER.error("消息卡号为空");
            return null;
        }
        GpsConnection conn = connctionMap.get(msg.getHeader().getSimId());
        if (conn == null) {
            conn = new GpsConnection(msg.getHeader().getSimId(), ctx);
            getConnctionMap().put(msg.getHeader().getSimId(), conn);
        }else {
            conn.setNettyChannel(ctx);
        }
        conn.setOnlineDate(new Date());

        return conn;
    }



    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {

        LOGGER.info("RamoteAddress : " + ctx.channel().remoteAddress() + " active !");

 //        ctx.channel().writeAndFlush( "Welcome to " + InetAddress.getLocalHost().getHostName() + " service!\n");
        ctx.channel().writeAndFlush("connect success");
        super.channelActive(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
 //        System.out.println(cause.getMessage());
        ctx.close();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        LOGGER.info("Channel is disconnected");
        super.channelInactive(ctx);
    }


    public boolean send(String simNo, byte[] msg) {
        GpsConnection conn = connctionMap.get(simNo);
        if (conn != null && conn.getNettyChannel() != null) {
            ByteBuf buff = Unpooled.buffer(msg.length);
            buff.writeBytes(msg);
            ChannelFuture future = conn.getNettyChannel().writeAndFlush(buff);
            future.addListener(new ChannelFutureListener() {
                public void operationComplete(ChannelFuture future) {
                    if (future.isSuccess()) {
                        LOGGER.debug(future.channel() + ",成功发送GPS数据.");
                    } else {
                        Channel channel = future.channel();
                        Throwable cause = future.cause();
                        LOGGER.error("当前channel[{"+channel+"}]发送GPS数据包失败.",cause);
                        conn.getNettyChannel().close();
                    }
                };
            });
        }
        return true;
    }

    public ConcurrentMap<String, GpsConnection> getConnctionMap() {
        return connctionMap;
    }

    public void setConnctionMap(ConcurrentMap<String, GpsConnection> connctionMap) {
        this.connctionMap = connctionMap;
    }



}
